#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

#define DEBUG 0

long calcRuntime(struct timeval *begin, struct timeval *end);

void orgBarrier(int *size,int *rank);

void barrier(int *rank);

void release(int *size);	

//MAIN
int main(int argc,char** argv)
{
	int rank,size = -1;
	int iterations = 0;
	int returnVal = 0;
	long runtime = 0;

	int i = 0;

	struct timeval start,end;

	MPI_Init(&argc,&argv);

	if(argc == 2){

		iterations = atoi(argv[1]);

		MPI_Comm_rank(MPI_COMM_WORLD,&rank);
		MPI_Comm_size(MPI_COMM_WORLD,&size);

		if(rank == 0){
			//Node with rank 0. Used to calculate the runtime.
			#if DEBUG == 1
				printf("#Node with rank %d started. Iterations: %d Size: %d \n",rank,iterations,size);
			#endif

			printf("#\"No. of Nodes\" Iterations Runtime \"Over all Runtime\"\n");

			gettimeofday(&start,NULL);

			for(i = 0; i < iterations; i++){
				#if DEBUG == 1
					printf("#Node %d starting loop.\n",rank);
				#endif
				//int MPI_Barrier(MPI_Comm comm)
				MPI_Barrier(MPI_COMM_WORLD);
				
			}

			gettimeofday(&end,NULL);
			runtime = calcRuntime(&start,&end);

			printf("%d %d %ld %lf\n",size,iterations,runtime,(double)runtime/(double)iterations);
		}else{
			//worker Node
			#if DEBUG == 1
				printf("#Node with rank %d started.\n",rank);
			#endif
			for(i = 0; i < iterations; i++){
				#if DEBUG == 1
					printf("#Node %d starting loop.\n",rank);
				#endif
				MPI_Barrier(MPI_COMM_WORLD);
			}
		}
	}else{
		printf("#Error: Usage: ex02_2 <Number of Iterations>\n");
		returnVal = -1;
	}

	MPI_Finalize();

	return returnVal;
}

/*Function: calcRuntime()*/
long calcRuntime(struct timeval *begin, struct timeval *end){
	struct timeval diff;
	diff.tv_sec = end->tv_sec - begin->tv_sec;

	if(begin->tv_usec > end->tv_usec){
		diff.tv_usec = (1e6- end->tv_usec) + begin->tv_usec;
	}else{
		diff.tv_usec = end->tv_usec - begin->tv_usec;
	}

	return (diff.tv_sec * 1e6 + diff.tv_usec);
}

